#include <QApplication>
#include <QDesktopServices>
#include <QDir>
#include <QHBoxLayout>
#include <QLocale>
#include <QMenuBar>
#include <QMessageBox>
#include <QStyleFactory>
#include <QTranslator>

#include <lgpl-components/cobjectmanager.h>
#include <lgpl-components/dialogs/settingsdialog.h>

using namespace Core;
using namespace Core::Internal;

#include <messaginglayer/cmessaginglayer.h>

#include "actionmanager.h"
#include "contextmanager.h"
#include "icore.h"
#include "uidmanager.h"
#include "constants.h"
#include "contactswidget.h"
#include "icore.h"
#include "generalsettings.h"
#include "mainwindow.h"
#include "messagingwidget.h"
#include "rightpane.h"
#include "startupwidget.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent),
    m_core(new ICore(this)),
    m_generalSettings(new GeneralSettings(this))
{
    resize(640, 480);

    loadTranslations();
    QDesktopServices::setUrlHandler("help", this, "openHelp");

    m_rightPane = new RightPane(this);
    m_core->objectManager()->add(m_generalSettings);

    createWindowLayout();
    connect(m_startupWidget, SIGNAL(connectionRequest(CAuthInfo)), this, SLOT(changeProfile(CAuthInfo)));
    connect(m_core->messagingLayer(), SIGNAL(messageReceived(CMessage)),
            this, SLOT(profileMessageReceived(CMessage)));
}

MainWindow::~MainWindow()
{

}

void MainWindow::createWindowLayout()
{
    QWidget * w = new QWidget(this);
    QHBoxLayout * l = new QHBoxLayout(w);
    ContextManager * cm = m_core->contextManager();

    l->addWidget(cm->widget());
    m_rightPane->setFixedWidth(250);
    m_rightPane->setVisible(false);
    l->addWidget(m_rightPane);

    setCentralWidget(w);
    createActions();

    m_startupWidget = new StartupWidget(this);
    m_contactsWidget = new ContactsWidget(this);
    m_messagingWidget = new MessagingWidget(this);

    connect(cm, SIGNAL(currentChanged()), this, SLOT(contextChanged()));
    registerContexts();
}

void MainWindow::createActions()
{
    ActionManager * am = m_core->actionManager();
    UidManager * uidm = m_core->uidManager();
    QAction * a = 0;

    // profile
    QMenu * profile = menuBar()->addMenu(tr("Profile"));
    a = profile->addAction(tr("Status"));
    am->addAction(a, QList<int>() << uidm->uniqueIndentifier(Constants::C_LOGED_IN));
    QMenu * statuses = new QMenu(this);
    statuses->addAction(tr("Online"));
    statuses->addAction(tr("Offline"));
    a->setMenu(statuses);
    profile->addSeparator();

    a = profile->addAction(tr("Change"));
    QMenu * changeProfile = new QMenu(this);
    changeProfile->addAction(tr("Other..."));
    changeProfile->addSeparator();
    changeProfile->addAction(tr("some1@vk.com"));
    changeProfile->addAction(tr("some2@vk.com"));
    changeProfile->addAction(tr("some3@vk.com"));
    a->setMenu(changeProfile);
    a = profile->addAction(tr("Exit"));
    am->addAction(a, QList<int>() << uidm->uniqueIndentifier(Constants::C_LOGED_IN));
    profile->addSeparator();

    profile->addAction(tr("Settings..."), this, SLOT(openSettingsDialog()));
    profile->addSeparator();    
    profile->addAction(tr("Quit"), qApp, SLOT(quit()));

    // contacts
    QMenu * contacts = menuBar()->addMenu(tr("Contacts"));
    contacts->addAction(tr("Search"));
    contacts->addSeparator();
    contacts->addAction(tr("Remove"));

    QMenu * view = menuBar()->addMenu(tr("View"));
    a = view->addAction(tr("Styles"));
    a->setMenu(populateStylesMenu());

    // help
    QMenu * help = menuBar()->addMenu(tr("Help"));
    help->addAction(tr("Index"), this, SLOT(openHelp()));
    help->addSeparator();
    help->addAction(tr("About..."), this, SLOT(aboutDialog()));
}

void MainWindow::contextChanged()
{
    ContextManager * cm = m_core->contextManager();
    UidManager * uidm = m_core->uidManager();

    m_rightPane->contextChanged();
    m_core->actionManager()->contextChanged(cm->currentContext());
}

QMenu * MainWindow::populateStylesMenu()
{
    QMenu * menu = new QMenu(this);
    QAction * act = 0;

    QStringList styles = QStyleFactory::keys();
    foreach (const QString &style, styles) {
        act = new QAction(style, this);
        act->setData(style);
        connect(act, SIGNAL(triggered()), this, SLOT(styleChangeRequest()));
        menu->addAction(act);
    }

    return menu;
}

void MainWindow::styleChangeRequest()
{
    QAction * a = qobject_cast<QAction *>(sender());

    if (a) {
        qApp->setStyle(a->data().toString());
    }
}

void MainWindow::openSettingsDialog(const QString &initialCategory, const QString &initialPage)
{
    SettingsDialog * dlg = SettingsDialog::getSettingsDialog(this, m_core->settings(), initialCategory, initialPage);

    dlg->resize(550, 360);
    dlg->exec();
}


void MainWindow::openHelp(const QUrl &url)
{
    QMessageBox::information(this, tr("Help not avaible"), tr("Help will be avaible in next releases."));
}

void MainWindow::aboutDialog()
{
    QMessageBox::about(this, tr("About"), QString(Constants::A_NAME).append("\n\n")
                       .append(tr("Version: %1 (%2)").arg(Constants::A_VERSION).arg(Constants::A_YEAR)));
}

void MainWindow::changeProfile(const CAuthInfo &authInfo)
{
    CMessagingLayer * mlayer = m_core->messagingLayer();

    if (authInfo.password().isEmpty())
        m_startupWidget->connectionError(tr("Enter password"));
    else {
        mlayer->setProfile(authInfo);
        m_contactsWidget->setContactsModel(mlayer->currentProfile()->contactsModel());
        emit profileChanged(mlayer->currentProfile());

        connect(mlayer->currentProfile(), SIGNAL(errorChanged(CProfile::Error)),
                this, SLOT(profileError(CProfile::Error)));
        connect(mlayer->currentProfile(), SIGNAL(stateChanged(CProfile::State)),
                this, SLOT(profileStateChanged(CProfile::State)));
        mlayer->connectProfile();
    }

}

void MainWindow::profileStateChanged(CProfile::State state)
{
    ContextManager * cm = m_core->contextManager();
    UidManager * uidm = m_core->uidManager();

    if (cm->currentGuiContext() == uidm->uniqueIndentifier(Constants::C_STARTUP)) {
        if (state == CProfile::Connecting)
            m_startupWidget->setProgressMessage(tr("Connecting..."));
        else if (state == CProfile::Connected)
            m_startupWidget->setProgressMessage(tr("Connected"));
        else if (state == CProfile::Authorizing)
            m_startupWidget->setProgressMessage(tr("Authorizing..."));
        else if (state == CProfile::Authorized)
            m_startupWidget->setProgressMessage(tr("Authorized"));
        else if (state == CProfile::LoadingContacts)
            m_startupWidget->setProgressMessage(tr("Loading contacts..."));
        else if (state == CProfile::ContactsLoaded) {
            m_startupWidget->connected();
            cm->setGuiContext(uidm->uniqueIndentifier(Constants::C_CONTACTS));
        }
    }
}

void MainWindow::profileError(CProfile::Error error)
{
    ContextManager * cm = m_core->contextManager();
    UidManager * uidm = m_core->uidManager();

    if (cm->currentGuiContext() == uidm->uniqueIndentifier(Constants::C_STARTUP)) {
        QString errorStr;

        if (error == CProfile::ConnectionError)
            errorStr = tr("Connection error");
        else if (error == CProfile::AuthorizationError)
            errorStr = tr("Invalid user or password");
        else
            errorStr = tr("Unknow error");
        m_startupWidget->connectionError(errorStr);
    }
}

void MainWindow::profileMessageReceived(const CMessage &message)
{
    QString msgText;
    QString name = message.from();
    ContactInfo cinfo;

    cinfo = m_core->messagingLayer()->resolveUid(message.from(), message.networkId());
    if (cinfo.isValid()) {
        name = cinfo.name();
    }

    msgText = QString("From: %1\nTo: %2\n\n%3").arg(name).arg(message.to()).arg(message.text());
    QMessageBox::information(this, tr("Incoming message"), msgText);
}

void MainWindow::openMessaging(const ContactInfo &cinfo)
{
    ContextManager * cm = m_core->contextManager();
    UidManager * uidm = m_core->uidManager();

    m_messagingWidget->setCurrentContact(cinfo);
    cm->setGuiContext(uidm->uniqueIndentifier(Constants::C_MESSAGING));
}

void MainWindow::loadTranslations()
{
    QString trPath = /*qApp->applicationDirPath() +*/ "../share/sii-storm/translations";
    QTranslator * qtTranslator = new QTranslator(this);
    QTranslator * appTranslator = new QTranslator(this);

    qtTranslator->load("qt_" + QLocale::system().name(), trPath);
    qApp->installTranslator(qtTranslator);

    appTranslator->load("sii-storm_" + QLocale::system().name(), trPath);
    qApp->installTranslator(appTranslator);
}

void MainWindow::registerContexts()
{
    ContextManager * cm = m_core->contextManager();
    UidManager * uidm = m_core->uidManager();

    uidm->uniqueIndentifier(Constants::C_GLOBAL); // == 0
    int cStartup = uidm->uniqueIndentifier(Constants::C_STARTUP);
    int cContacts = uidm->uniqueIndentifier(Constants::C_CONTACTS);
    int cMessaging = uidm->uniqueIndentifier(Constants::C_MESSAGING);

    cm->addGuiContext(cStartup, m_startupWidget);
    cm->addGuiContext(cContacts, m_contactsWidget);
    cm->addGuiContext(cMessaging, m_messagingWidget);
}
